import { ISignaLightConfig } from "../../renderer/src/interface";
import { IsignaLightStatus } from "./C300ProtocolHandler";
import { IDregister, SerialPortReader } from "./SerialPortReader";

export class FxProtocolHandler extends SerialPortReader {
  private recvFlag: boolean = false;
  private recvArray: number[] = [];
  private recvCount: number = 0; //本次接收数据除校验码的长度
  private recvCallback:
    | ((data: Buffer<ArrayBuffer>) => void | undefined)
    | undefined;

  constructor(path: string) {
    super({ path });
    //this.window = window;
  }
  // 处理接收到的数据
  public onDataReceived(data: Buffer<ArrayBuffer>): void {
    for (let i = 0; i < data.length; i++) {
      if (data[i] === 0x06 || data[i] === 0x15) {
        //接收正常　与不正常
        console.log("ACK_NAK",data);
        this.recvCallback && this.recvCallback(data);
        this.recvArray = [];
        break;
      }
      if (data[i] === 0x02) {
        this.recvArray = [0x02];
        this.recvFlag = true; //接收开始
        continue;
      } else if (data[i] === 0x03) {
        //收到接收停止符
        this.recvCount = this.recvArray.length;
      }

      if (this.recvFlag) {
        this.recvArray.push(data[i]);
      }

      if (this.recvCount && this.recvCount === this.recvArray.length - 3) {
        //接收完成
        this.recvFlag = false;
        this.recvCallback && this.recvCallback(Buffer.from(this.recvArray));
        this.recvArray = [];
        this.recvCount = 0;
      }
    }
  }

  //生成校验码
  private generateCheckCode(
    buf: Buffer<ArrayBuffer>,
    start: number,
    end: number = buf.length
  ): Buffer<ArrayBuffer> {
    let code: string | number = 0;
    for (let i = start; i < end; i++) {
      code += buf[i];
    }
    code &= 0xff;
    return Buffer.from(this.addLeadingZero(code.toString(16).toUpperCase()));
  }

  //生成发送数据Buf
  private generateSendData(content: string) {
    let buf = Buffer.alloc(content.length + 2);
    buf[0] = 0x02;
    const contentBuf = Buffer.from(content);
    for (let i = 0; i < content.length; i++) {
      buf[i + 1] = contentBuf[i];
    }
    buf[content.length + 1] = 0x03;
    const code = this.generateCheckCode(buf, 1, content.length + 2);
    return Buffer.concat([buf, code]);
  }

  //校验接收的数据返回布尔
  private checkRecvData(buf: Buffer<ArrayBuffer>, size: number): boolean {
    if (buf.length > 4 && buf.length - 4 === size * 2) {
      if (
        buf.toString().substring(buf.length - 2) ===
        this.generateCheckCode(buf, 1, size * 2 + 2).toString()
      )
        return true;
      else return false;
    } else {
      return false;
    }
  }

  //同步发送接收
  private asyncSendRecv(
    buf: Buffer<ArrayBuffer>
  ): Promise<Buffer<ArrayBuffer> | undefined> {
    this.send(buf);
    return new Promise((resolve) => {
      let timer = setTimeout(resolve, 500);
      this.recvCallback = (data: Buffer<ArrayBuffer>) => {
        resolve(data);
        clearTimeout(timer);
      };
    });
  }

  //添加前导0
  private addLeadingZero(str: string, isUint16: boolean = false) {
    if (str.length <= 2 && isUint16) str = "00" + str;
    if (str.length % 2) {
      return "0" + str;
    }
    return str;
  }

  //生成发送主体内容
  private generateSendContent(
    type: "D" | "M",
    addr: number,
    size: number,
    mode: "wirte" | "read" = "wirte"
  ): string {
    let sendStr = "E10";
    if (mode === "read") {
      sendStr = "E00";
    }
    if (type === "M") {
      //M点
      addr = Math.floor(addr / 8);
    } else if (type === "D") {
      addr = 0x4000 + addr * 2;
    }
    sendStr += this.addLeadingZero(addr.toString(16).toUpperCase(), true); //地址转换
    sendStr += this.addLeadingZero(size.toString(16).toUpperCase()); //加数据大小
    return sendStr;
  }

  //读寄存器
  public async readDregister(
    type: "M" | "D",
    addr: number,
    size: number
  ): Promise<IDregister | undefined> {
    if (size < 2) size = 2; //最低读取长度为2个字节
    let sendStr = this.generateSendContent(type, addr, size, "read");
    const sendBuf = this.generateSendData(sendStr);
    
    const recvData = await this.asyncSendRecv(sendBuf);
    console.log(recvData)
    if (recvData && this.checkRecvData(recvData, size)) {
      const dataStr = recvData.toString().substring(1, recvData.length - 3);
      const dataBuf = Buffer.alloc(dataStr.length / 2);
      for (let i = 0; i < dataBuf.length; i++) {
        dataBuf[i] = parseInt(dataStr.substring(i * 2, i * 2 + 2), 16);
      }
      const dataUint16: number[] = [];
      const dataUint32: number[] = [];

      for (let i = 0; i < size / 2; i++) {
        dataUint16.push(dataBuf.readUint16LE(i * 2));
      }
      if (size >= 4)
        for (let i = 0; i < Math.floor(size / 4); i++) {
          dataUint32.push(dataBuf.readUint32LE(i * 4));
        }

      return { dataStr, dataBuf, dataUint16, dataUint32 };
    }
    return;
  }

  // 读位数据
  public async readBitsData(addr: number, size: number) {
    const obj = await this.readDregister("M", addr, size);
    if (!obj) return;
    const bits: boolean[] = [];
    for (let i = 0; i < obj.dataBuf.length; i++) {
      for (let j = 0; j < 8; j++) {
        bits[i * 8 + j] = ((obj.dataBuf[i] >> j) & 0x01) > 0;
      }
    }
    return {
      startM: addr - (addr % 8),
      buf: obj.dataBuf,
      bits,
    };
  }
  //写寄存器16位
  public async wirteUint16register(addr: number, data: number[]) {
    addr = 0x4000 + addr * 2;
    let sendStr = "E10";
    sendStr += addr.toString(16).toUpperCase(); //地址转换
    sendStr += this.addLeadingZero(
      (data.length * 2).toString(16).toUpperCase()
    ); //加数据大小
    for (let i = 0; i < data.length; i++) {
      const b = Buffer.alloc(2);
      b.writeUint16LE(data[i]); //写入BUF
      sendStr += this.addLeadingZero(b.toString("hex").toUpperCase()); //转16字符串再转ASC码
    }
    //console.log(this.generateSendData(sendStr));
    let sendBuf = await this.asyncSendRecv(this.generateSendData(sendStr));
    if (!sendBuf || sendBuf[0] === 0x15) return false;
    return true;
  }
  //写寄存器32位
  public wirteUint32register(addr: number, data: number[]) {
    const arrUint16: number[] = [];
    for (let i = 0; i < data.length; i++) {
      arrUint16.push(data[i] & 0xff);
      arrUint16.push((data[i] >> 8) & 0xff);
    }
    return this.wirteUint16register(addr, arrUint16);
  }

  //写M继电器
  public async wirteMbit(addr: number, sw: boolean) {
    let sendStr = "E";
    if (sw) sendStr += 7;
    else sendStr += 8;
    sendStr += this.addLeadingZero(addr.toString(16), true).substring(2);
    sendStr += this.addLeadingZero(addr.toString(16), true).substring(0, 2);

    let sendBuf = await this.asyncSendRecv(this.generateSendData(sendStr));
    //console.log(sendBuf);
    if (!sendBuf || sendBuf[0] === 0x15) return false;
    return true;
  }

  public async getRealTimeStatus(): Promise<IsignaLightStatus | undefined> {
    const data = await this.readDregister("D", 0, 20);
    if (!data) return;
    const devDate = new Date((data.dataUint32![4] + 946684800) * 1000);
    const curStatus: IsignaLightStatus = {
      rtc: devDate.toISOString().slice(0, 19).replace("T", " "),
      phaseTime: data.dataUint16[1],
      time: data.dataUint16[0],
      status: [],
    };
    curStatus.status = [data.dataUint16[2]];
    curStatus.status.push(data.dataUint16[3]);
    curStatus.status.push(data.dataUint16[4]);
    curStatus.status.push(data.dataUint16[5]);

    return curStatus;
  }

  private changeLight(d: number) {
    if (d & 4) {
      return 4;
    } else if (d & 1) return 1;
    else return 0;
  }

  public async getSchemeList(
    index: number
  ): Promise<ISignaLightConfig[][] | undefined> {
    const data = await this.readDregister("D", 3001 + index * 80, 160);
    if (!data) return;
    const schemeList: ISignaLightConfig[][] = [];
    //console.log(data);
    for (let i = 0; i < 4; i++) {
      const slcs: ISignaLightConfig[] = [];
      for (let j = 0; j < 16; j++) {
        if (data!.dataUint16[64 + j] === 0) continue;
        slcs.push({
          zuo: this.changeLight(data!.dataUint16[i * 16 + j] & 0xf),
          zhi: this.changeLight((data!.dataUint16[i * 16 + j] >> 4) & 0x0f),
          you: this.changeLight((data!.dataUint16[i * 16 + j] >> 8) & 0x0f),
          renxing: this.changeLight(
            (data!.dataUint16[i * 16 + j] >> 12) & 0x0f
          ),
        });
        if (i == 3) slcs[j].time = data!.dataUint16[64 + j];
      }
      schemeList.push(slcs);
    }

    return schemeList;
  }


  public async downloadSchemeList(list:string,schemeNum:number){
    const dataUint16List = new Array<number>(80).fill(0)
    const schemeList:ISignaLightConfig[][] = JSON.parse(list)
    
    for(let i=0;i<4;i++){
      for(let j=0;j<schemeList[i].length;j++){
        let temp = 0;
        const scheme = schemeList[i][j]
        temp |= scheme.zuo
        temp |= (scheme.zhi << 4)
        temp |= (scheme.you << 8)
        temp |= (scheme.renxing << 12)
  /*       if(scheme.zuo===1)
           temp |= 0x01 
        else if(scheme.zuo===4)
          temp |= 0x04
        if(scheme.zhi === 1)
          temp |= 0x10
        else if(scheme.zhi ===2)
          temp |= 0x40
        if(scheme.you === 1)
          temp |= 0x100
        else if(scheme.you ===2)
          temp |= 0x400
        if(scheme.renxing === 1)
          temp |= 0x1000
        else if(scheme.renxing ===2)
          temp |= 0x4000 */

        dataUint16List[i*16 + j] = temp
        if(i===3)
          dataUint16List[i*16 + j + 16] = scheme.time!
      }
    }
    console.log(JSON.stringify(dataUint16List))
    
    return await this.wirteUint16register(3001 + schemeNum * 80 ,dataUint16List)

  }


  public async applyScheme(){
    return await this.wirteMbit(7679,true)
  }
}
